﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace AutomatedDecisionMaking.Class.Algorithms
{
    class MinRegretAlgorithm
    {
        private readonly DecisionMatrix _mDecisionMatrix;       /// Macierz decyzji
        private readonly List<List<double>> _mRegretMatrix;     /// Macierz żalu
        private readonly List<double> _mListMaxInRowValue;      /// Maksymalna wartość w wierszu
        private readonly List<string> _mStrListMaxInRowValue;   /// Maksymalne wartości w wierszach w odpowiedni przygotowanym formacie string
        private readonly List<double> _mListMaxValue;           /// Lista maksymalnych wartości z poszczególnych wierszy macierzy żalu
        private readonly List<string> _mStrListMaxValue;        /// Lista maksymalnych wartości z poszczególnych wierszy macierzy żalu w formacie STRING
        private double _mMaxMinVal;                             /// Minimalna wartość z pośród maksymalnych
        private string _mDecision;                              /// Podjęta decyzja

        /// <summary>
        /// Konstruktor algorytmu realizującego kryterium najmniejszego żalu.
        /// </summary>
        /// <param name="decisionMatrix">Macierz decyzji wprowadzona porzez użytkownika</param>
        public MinRegretAlgorithm(DecisionMatrix decisionMatrix)
        {
            _mStrListMaxValue = new List<string>();
            _mListMaxValue = new List<double>();
            _mListMaxInRowValue = new List<double>();
            _mStrListMaxInRowValue = new List<string>();
            _mRegretMatrix = new List<List<double>>();
            _mDecisionMatrix = decisionMatrix;
            
        }

        /// <summary>
        /// Uruchomienie algorytmu i rozwiązanie postawionego zadania
        /// </summary>
        public void CalculateSolution()
        {
            CalculateRegretMatrix();
            for (int i = 0; i < _mRegretMatrix.Count; ++i)
            {
                string element = _mDecisionMatrix.DecisionList.ElementAt(i);
                double maxVal = _mRegretMatrix[i].Max();
                _mStrListMaxValue.Add(element + " : max = "+ maxVal);
                _mListMaxValue.Add(maxVal);
            }

            _mMaxMinVal = _mListMaxValue.Min();
            _mDecision = _mDecisionMatrix.DecisionList.ElementAt(_mListMaxValue.FindIndex(w => w == _mMaxMinVal));
        }

        /// <summary>
        /// Dostęp do podjętej decyzji
        /// </summary>
        /// <returns>Podjęta decyzja</returns>
        public string GetDecision()
        {
            return _mDecision;
        }

        /// <summary>
        /// Dostęp do największej w pośród najmniejszych wartości
        /// </summary>
        /// <returns>Największa z najmniejszych wartości</returns>
        public double GetMaxMinValue()
        {
            return _mMaxMinVal;
        }

        /// <summary>
        /// Największe wartości w wierszach w formacie string
        /// </summary>
        /// <returns>Wartości maksymalne w wierszach</returns>
        public List<string> GetMaxValuesStr()
        {
            return _mStrListMaxValue;
        }

        /// <summary>
        /// Największe wartości w wierszach w formacie
        /// </summary>
        /// <returns>Wartości maksymalne w wierszach</returns>
        public List<double> GetMaxValues()
        {
            return _mListMaxValue;
        }

        /// <summary>
        /// Dostęp do macierzy żalu
        /// </summary>
        /// <returns>Macierz żalu</returns>
        public List<List<double>> GetRegretMatrix()
        {
            return _mRegretMatrix;
        }  // Macierz żalu
        
        /// <summary>
        /// Najwięsze wartości w rzędach
        /// </summary>
        /// <returns>Nawiększe wartości w rzędach</returns>
        public List<double> GetMaxInRows()
        {
            return _mListMaxInRowValue;
        }

        /// <summary>
        /// Najwięsze wartości w rzędach
        /// </summary>
        /// <returns>Nawiększe wartości w rzędach</returns>
        public List<string> GetMaxInRowsStr()
        {
            return _mStrListMaxInRowValue;
        }

        /// <summary>
        /// Dostęp do macierzy decyzji
        /// </summary>
        /// <returns>Macierz decyzji</returns>
        public DecisionMatrix GetDecisionMatrix()
        {
            return _mDecisionMatrix;
        }

        /// <summary>
        /// Wyznaczenie macierzy żalu
        /// </summary>
        private void CalculateRegretMatrix()
        {
            int decisionNo = _mDecisionMatrix.DecisionList.Count;
            for(int i=0; i<decisionNo; ++i)
            {
                List<double> decisionRow = _mDecisionMatrix.Value[i];
                _mListMaxInRowValue.Add(decisionRow.Max());

                string element = _mDecisionMatrix.DecisionList.ElementAt(i);
                _mStrListMaxInRowValue.Add(element + " : max = " + decisionRow.Max());
                _mRegretMatrix.Add(decisionRow.ConvertAll(w => Math.Abs(w - _mListMaxInRowValue[i])));
            }
        }
    }
}
